﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

namespace WpfApp1
{
    /// <summary>
    /// Window1.xaml 的交互逻辑
    /// 
    /// 
    /// Window lifetime events
    /// https://docs.microsoft.com/zh-cn/dotnet/desktop/wpf/windows/?view=netdesktop-6.0#window-lifetime-events
    /// </summary>
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
        }

        /// <summary>
        /// 当一个窗口打开时，它在相对于桌面的x和y维度中有一个位置。这个位置可以通过分别检查Left和Top属性来确定。
        /// 设置这些属性以更改窗口的位置。
        /// 
        /// 你也可以指定窗口的初始位置，当它第一次出现，通过设置WindowStartupLocation属性与下列WindowStartupLocation枚举值之一:
        /// 1. CenterOwner (default)
        /// 2. CenterScreen
        /// 3. Manual
        /// 
        /// 如果启动位置被指定为“Manual”，并且“Left”和“Top”属性还没有设置，Window将会向操作系统询问要出现的位置。
        /// https://docs.microsoft.com/zh-cn/dotnet/desktop/wpf/windows/?view=netdesktop-6.0#window-location
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Window_SourceInitialized(object sender, EventArgs e)
        {
            MessageBox.Show($"Location: Left {this.Left}, Top {this.Top}. WindowStartupLocation: {this.WindowStartupLocation}");

        }

        /// <summary>
        /// 
        /// 除了具有x和y位置外，窗口还具有z维位置，这决定了它相对于其他窗口的垂直位置。这就是所谓的窗口z轴次序，
        /// 有两种类型:`normal`z轴次序和`topmost`z轴次序。
        /// 
        /// 在`normal`z轴次序中，窗口的位置是由它当前是否处于活动状态决定的。默认情况下，窗口位于正常的z轴顺序中。
        /// 窗口在最高z轴顺序中的位置也取决于它当前是否处于活动状态。
        /// 
        /// 此外，位于最高z轴次序的窗口总是位于`normal`z轴次序的窗口之上。通过将Topmost属性设置为true，窗口位于最顶端的z轴顺序。
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            // 
            this.Topmost = true;
        }

        /// <summary>
        /// 当窗口第一次打开时，它就成为活动窗口。活动窗口是当前捕获用户输入(如击键和鼠标单击)的窗口。当窗口变为活动状态时，
        /// 它将引发Activated事件。
        /// 
        /// 当窗口首次打开时，只有在Activated事件被引发之后才会引发 Loaded 和 ContentRendered 事件。考虑到这一点，
        /// 当 ContentRendered 被引发时，窗口可以被认为是打开的。
        /// 
        /// 当一个窗口变为活动状态后，用户可以激活同一应用程序中的另一个窗口，或激活另一个应用程序。当这种情况发生时，
        /// 当前活动的窗口将失去激活并引发 Deactivated 事件。同样，当用户选择当前未激活的窗口时，该窗口再次变为激活的，
        /// 并将引发 Activated 事件。
        /// 
        /// 处理Activated和Deactivated的一个常见原因是启用和禁用只能在窗口处于活动状态时运行的功能。例如，有些窗口
        /// 显示需要用户持续输入或关注的交互式内容，包括游戏和视频播放器。
        /// 
        /// 下面的示例是一个简化的视频播放器，演示了如何处理Activated和Deactivated来实现此行为。
        /// 
        /// https://docs.microsoft.com/zh-cn/dotnet/desktop/wpf/windows/?view=netdesktop-6.0#window-activation
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Window_Activated(object sender, EventArgs e)
        {
            //MessageBox.Show($"\"{Title}\" Window Activated!");

            // Continue playing media if window is activated
            //mediaElement.Play();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Window_Deactivated(object sender, EventArgs e)
        {
            //MessageBox.Show($"\"{Title}\" Window Deactivated!");

            // Pause playing if media is being played and window is deactivated
            //mediaElement.Pause();
        }

        /// <summary>
        /// 要关闭窗口以响应这些自定义机制之一，需要调用close方法。下面的示例实现了通过从“File”菜单中选择“Exit”
        /// 来关闭窗口的功能。
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void fileExitMenuItem_Click(object sender, RoutedEventArgs e)
        {
            // Close the current window
            this.Close();
        }

        private bool _isDataDirty;
        /// <summary>
        /// 当窗口关闭时，它会引发两个事件:Closing和Closed。
        /// Closing是在窗口关闭之前触发的，它提供了一种机制，通过这种机制可以防止窗口关闭。防止窗口关闭的一个常见原因是
        /// 窗口内容包含修改过的数据。在这种情况下，可以处理Closing事件来确定数据是否脏，如果是，则询问用户是继续关闭窗
        /// 口而不保存数据还是取消窗口关闭。
        /// 下面的示例展示了处理Closing的关键方面。
        /// 
        /// https://docs.microsoft.com/zh-cn/dotnet/desktop/wpf/windows/?view=netdesktop-6.0#cancel-window-closure
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void documentTextBox_TextChanged(object sender, TextChangedEventArgs e) =>
            _isDataDirty = true;

        /// <summary>
        /// Closing事件处理程序被传递一个CancelEventArgs，它实现了Cancel属性，您将该属性设置为true以防止窗口关闭。
        /// 如果关闭未被处理，或者已被处理但未被取消，窗口将关闭。
        /// 
        /// 在窗口实际关闭之前，将引发Closed。此时，无法阻止窗口关闭。
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            // If data is dirty, prompt user and ask for a response
            if (_isDataDirty)
            {
                var result = MessageBox.Show("Document has changed. Close without saving?",
                                             "Question",
                                             MessageBoxButton.YesNo);

                // User doesn't want to close, cancel closure
                if (result == MessageBoxResult.No)
                    e.Cancel = true;
            }
        }


        private void Button_Click(object sender, RoutedEventArgs e)
        {
            MessageBox.Show("Button was clicked.");
        }

        private void ButtonShowInTaskbar_Click(object sender, RoutedEventArgs e)
        {
            MessageBox.Show($"{this.ShowInTaskbar}");
            // ShowInTaskbar 值默认为 true，表示缩小到任务栏中，变成常见的任务栏按钮。值设为false时，将会
            // 折叠到尽可能小的尺寸，并移动到桌面的左下角。这两种最小化窗口都不能使用边框或重设手柄来
            // 调整大小，不过任务栏中没有显示的最小化窗口可以在桌面上拖动。
            this.ShowInTaskbar = !this.ShowInTaskbar;
        }

        private void ButtonWindowMaximized_Click(object sender, RoutedEventArgs e)
        {
            this.WindowState = WindowState.Maximized;
        }

        private void ButtonWindowMinimized_Click(object sender, RoutedEventArgs e)
        {
            this.WindowState = WindowState.Minimized;
        }

        /// <summary>
        /// 更改非客户端区域边界的外观和行为
        /// 
        /// 配置窗口的调整大小模式（resize mode）、窗口样式（window style）以及是否在桌面任务栏中显示为按钮。
        /// 
        /// https://docs.microsoft.com/zh-cn/dotnet/desktop/wpf/windows/?view=netdesktop-6.0#window-appearance
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ButtonWindowNonclientAreaChange_Click(object sender, RoutedEventArgs e)
        {
            // ResizeMode
            // 根据WindowStyle属性，您可以控制用户是否以及如何调整窗口的大小。窗口样式会影响以下内容:
            // 1. 允许或不允许用鼠标拖动窗口边框来调整大小。
            // 2. “最小化”、“最大化”和“关闭”按钮是否出现在非客户端区域。
            // 3. “最小化”、“最大化”和“关闭”按钮是否启用。

            // 你可以通过设置窗口的ResizeMode属性来设置窗口的大小，它可以是以下ResizeMode枚举值之一:
            // 1. NoResize
            // 2. CanMinimize
            // 3. CanResize(default)
            // 4. CanResizeWithGrip

            // 与WindowStyle一样，窗口的调整大小模式在其生命周期内不太可能改变，这意味着您很可能从XAML标记设置它。
            // 注意，您可以通过检查WindowState属性来检测窗口是否被最大化、最小化或恢复。

            this.ResizeMode = ResizeMode.CanResizeWithGrip;


            // Window style
            // 从窗口的非客户端区域公开的边界适合于大多数应用程序。然而，在某些情况下需要不同类型的边框，或者根本不需要边框，
            // 这取决于窗口的类型。

            // 要控制窗口的边框类型，你可以用下面的 WindowStyle 枚举值来设置它的WindowStyle属性:
            // 1. None
            // 2. SingleBorderWindow(default)
            // 3. ThreeDBorderWindow
            // 4. ToolWindow

            var arr = Enum.GetValues<WindowStyle>();
            var random = new Random();
            this.WindowStyle = arr[random.Next(arr.Length)];
            MessageBox.Show($"{this.WindowStyle}");


            // Non-rectangular window style 非矩形窗口样式
            // 还有一些情况下，WindowStyle允许你拥有的边框样式并不足够。例如，您可能希望创建一个具有非矩形边框的应用程序，
            // 就像Microsoft Windows Media Player所使用的那样。

            // 这种类型的窗口可以通过将WindowStyle属性设置为None，并使用window对透明度的特殊支持来创建。

            // 这些值的组合指示窗口呈现透明。在这种状态下，窗口的非客户区装饰按钮不能使用，您需要提供自己的。


            // Task bar presence
            // 窗口的默认外观包括一个任务栏按钮。有些类型的窗口没有任务栏按钮，例如消息框、对话框或将WindowStyle属性设置
            // 为ToolWindow的窗口。您可以通过设置ShowInTaskbar属性来控制是否显示窗口的任务栏按钮，该属性默认为true。
            this.ShowInTaskbar = !this.ShowInTaskbar;
        }
    }
}
